package com.zyf.channel.plugin


import android.content.Context
import com.android.build.api.artifact.SingleArtifact
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
import com.bigzhao.xml2axml.Encoder
import com.bigzhao.xml2axml.test.AXMLPrinter
import net.dongliu.apk.parser.ApkFile
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider
import java.io.File
import java.io.PrintStream
import java.util.Properties


class ChannelPlugin:Plugin<Project> {
    private var manifest:Provider<RegularFile>?= null
    private var apkPath:Provider<Directory>?= null
    override fun apply(project: Project) {
        val extension = project.extensions.create<ChannelPluginExtension>("channelConfig", ChannelPluginExtension::class.java)

        val androidComponents = project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java)


        androidComponents.onVariants { variant ->
            if (variant.buildType == "release") {
                val apkProvider = variant.artifacts.get(SingleArtifact.APK)
                apkPath = apkProvider
                manifest = variant.artifacts.get(SingleArtifact.MERGED_MANIFEST)
            }
        }
        val printApkPaths = project.tasks.register("printApkPaths") {
            it.doLast {
                println("apkPath>>${apkPath?.orNull?.asFile?.absolutePath}")
                apkPath?.orNull?.asFile?.run {
                    println("apkPath>>${absolutePath}")
                    println("apkPath>>${name}")
                    if (!extension.keystore.exists()){
                        println("请配置keystore文件路径")
                        return@doLast
                    }
                    if (extension.alias.isEmpty()){
                        println("请配置alias")
                        return@doLast
                    }
                    if (extension.keyPass.isEmpty()){
                        println("请配置keyPass")
                        return@doLast
                    }
                    if (extension.storePass.isEmpty()){
                        println("请配置storePass")
                        return@doLast
                    }
                    if (isDirectory){
                        for (file in listFiles()){
                            if (file.extension == "apk"){
                                //读取apk配置
                                val channelDir = project.layout.buildDirectory.dir("outputs").get().dir("channelApk").asFile
                                if (!channelDir.exists()) {
                                    channelDir.mkdirs()
                                }
                                if (file.exists()){
                                    deleteFile(channelDir)//清空文件夹
                                    val unzipApkPath= unzipApk(project,file,channelDir)
                                    val manifest = File(unzipApkPath,"AndroidManifest.xml")
                                    val manifestOut = File(channelDir,"AndroidManifest.xml")
                                    AXMLPrinter.out = PrintStream(manifestOut)
                                    if (!manifestOut.exists()){
                                        manifestOut.createNewFile()
                                    }
                                    AXMLPrinter.main(arrayOf<String>(manifest.absolutePath))
                                    AXMLPrinter.out.close()
                                    val channelFile = File(extension.channelFilePath)
                                    println("${extension.channelFilePath}")
                                    if (channelFile.exists()){
                                        readChannel(channelFile,file,unzipApkPath,channelDir,extension,project)
                                        println("自定义配置channel.properties")
                                    }else{
                                        val defFile = project.layout.projectDirectory.file("channel.properties").asFile
                                        if (defFile.exists()) {
                                            readChannel(defFile,file,unzipApkPath,channelDir,extension,project)
                                            println("默认配置channel.properties")
                                        }else{
                                            println("渠道配置文件不存在，请在app目录下创建channel.properties文件或者配置channel.properties文件路径")
                                        }
                                    }
                                }
                            }
                        }
                    }

                }
            }
        }
        project.tasks.whenTaskAdded { task ->
            if (task.name == "assembleRelease") {
                task.finalizedBy(printApkPaths)
            }
        }
    }


    private fun unzipApk(project: Project,oApk: File,root:File):String{
        val zipApkPath = File(root.path+"/zipApk")
        if (zipApkPath.exists()){
            zipApkPath.mkdirs()
        }
        project.copy {
            it.from(project.zipTree(oApk))
            it.into(zipApkPath)
        }
        return zipApkPath.absolutePath
    }
    //解析channel文件
    private fun readChannel(channelFile: File,oApk: File,unzipApkPath:String,channelDir:File,extension: ChannelPluginExtension,project: Project){
        val encoder =Encoder()
        val apkFile = ApkFile(oApk)
        val channelProperties = Properties()
        val inputStream = channelFile.inputStream()
        channelProperties.load(inputStream)
        for (key in channelProperties.keys()) {
            val id = channelProperties.getProperty(key.toString())
            val replaceMan = File(channelDir,"AndroidManifest.xml").readText()
                .replace("\${CHANNEL_ID}", "mi")
                .replace("\${CHANNEL_NAME}", "小米市场")
            replaceManifest(replaceMan,key.toString(),id,encoder,channelDir,unzipApkPath)
            //压缩unzipApkPath文件到channelDir下生成apk文件
            val zipalign = channelDir.path+"/zipalign"
            if (!File(zipalign).exists()){
                File(zipalign).mkdirs()
            }
            val apkName = "/${apkFile.apkMeta.name}_${apkFile.apkMeta.versionName}_${key}.apk"
            val unZipalignApk = File(zipalign,apkName)
            ZipUtils.zipFolder(File(unzipApkPath),unZipalignApk)

            val aligned = channelDir.path+"/aligned"
            if (!File(aligned).exists()){
                File(aligned).mkdirs()
            }

            val signed = channelDir.path+"/signed"
            if (!File(signed).exists()){
                File(signed).mkdirs()
            }
            apkSign(unZipalignApk,File(aligned,apkName),File(signed,apkName),extension,project)
        }
        deleteFile(File(unzipApkPath))
    }


    private fun replaceManifest(manifestXml: String,channelName:String,channelId:String,encoder: Encoder,channelDir:File,unzipApkPath:String){
        // 替换 Manifest 中的占位符
        val modifiedXml = manifestXml
            .replace("\$CHANNEL_ID", channelId)
            .replace("\$CHANNEL_NAME", channelName)
        println("CHANNEL_NAME:${channelName}  CHANNEL_ID:${channelId}")
        val byte = encoder.encodeString(Context(), modifiedXml)
        //写入root目录下的AndroidManifest.xml文件中原来文件有类容需要清空
        val manifestFile = File(unzipApkPath, "AndroidManifest.xml")
        if (manifestFile.exists()) {
            manifestFile.delete()
        }
        manifestFile.writeBytes(byte)
    }


    private fun deleteFile(dir: File){
        println("开始删除旧文件")
        if (dir.exists() && dir.isDirectory) {
            // 获取目录下的所有文件和子目录，并逐个删除
            dir.listFiles()?.forEach { file ->

                val state= file.deleteRecursively()
                println("删除>>${file.name}>>${if (state) "成功" else "失败"}")
            }
        }
        println("删除旧文件完成")
    }


    private fun apkSign(zipApk:File,alignedApk:File,signedApk:File,extension: ChannelPluginExtension,project: Project){
        println("📐 ZIP 对齐中...")
        val zipalignCmd = listOf(
            ApkSignUtils.getBuildTool("zipalign",project),
            "-p", "-f", "4",
            zipApk.absolutePath,
            alignedApk.absolutePath
        )
        ApkSignUtils.runCommand(zipalignCmd)
        zipApk.delete()
        println("🔏 APK 签名中...")
        val apksignerCmd = listOf(
            ApkSignUtils.getBuildTool("apksigner",project),
            "sign",
            "--ks", extension.keystore.absolutePath,
            "--ks-key-alias", extension.alias,
            "--ks-pass", "pass:${extension.storePass}",
            "--key-pass", "pass:${extension.keyPass}",
            "--v4-signing-enabled","${false}",
            "--v1-signing-enabled","${true}",
            "--out", signedApk.absolutePath,
            alignedApk.absolutePath
        )
        ApkSignUtils.runCommand(apksignerCmd)
        alignedApk.delete()
        println("✅ 签名 APK 输出: ${signedApk.absolutePath}")
    }
}
